﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Xaml;
using System.Xml;
using System.Drawing;
using System.Xml.XPath;

namespace HtmlEditor
{
    /// <summary>
    /// RichTextEditor.xaml 的交互逻辑
    /// </summary>
    public partial class RichTextEditor : UserControl, INotifyPropertyChanged
    {
        #region 字段

        private static readonly string VisualFontFamiliesPath = @"/htmleditor/visualmode/fontfamilies/add/@value";
        private static readonly string SourceFontFamilyPath = @"/htmleditor/sourcemode/fontfamily/@value";
        private static readonly string SourceFontSizePath = @"/htmleditor/sourcemode/fontsize/@value";
        private Window hostedWindow;

        #endregion
        public RichTextEditor()
        {
            Global.ResPath = System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName);
            Global.CacheImagePath = Global.ResPath + "\\cache\\";
            Global.FaceImagePath = Global.ResPath + "\\res\\face\\";
            InitializeComponent();
            Lodding();
            InitEvents();
        }

        #region 属性
        private string _xaml = String.Empty;
        private string _text = String.Empty;
        private ArrayList _images = new ArrayList();
        /// <summary>
        /// 获取纯文本
        /// </summary>
        public string Text
        {
            get
            {
                return this._text;
            }
            set
            {
                if (this._text == value)
                    return;
                this._text = value;
                this.RaisePropertyChanged("Text");
            }
        }
        /// <summary>
        /// 获取图片地址
        /// </summary>
        public ArrayList Images
        {
            get
            {
                return this._images;
            }
            set
            {
                if (this._images == value)
                    return;
                this._images = value;
                this.RaisePropertyChanged("Images");
            }
        }
        /// <summary>
        /// 获取 HTML 格式文本
        /// </summary>
        public string Html
        {
            get
            {
                return RichTextBoxHelper.GetHtml(this.rtbXaml);
            }
        }
        /// <summary>
        /// 获取 XAML 格式文本
        /// </summary>
        public string Xaml
        {
            get
            {
                return this._xaml;
            }
            set
            {
                if (this._xaml == value)
                    return;
                this._xaml = value;
                this.RaisePropertyChanged("Xaml");
            }
        }
        #endregion

        #region 依赖属性 绑定

        private string _bindingHtml = String.Empty;
        private string _bindingXaml = String.Empty;
        private string _backGroundImagePath = String.Empty;

        public static DependencyProperty BackGroundProperty = DependencyProperty.Register("BindingBackGroundImage",
                                                        typeof(String),
                                                        typeof(RichTextEditor),
                                                        new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(OnBindingBackGroundChanged)));
        public static DependencyProperty HtmlProperty = DependencyProperty.Register("BindingHTML",
                                                        typeof(String),
                                                        typeof(RichTextEditor),
                                                        new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(OnBindingHtmlChanged)));
        public static DependencyProperty XamlProperty = DependencyProperty.Register("BindingXAML",
                                                        typeof(String),
                                                        typeof(RichTextEditor),
                                                        new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(OnBindingXamlChanged)));
        /// <summary>
        /// 背景图片
        /// </summary>
        public string BindingBackGroundImage
        {
            get { return (String)GetValue(BackGroundProperty); }
            set
            {
                SetValue(BackGroundProperty, value);
            }
        }
        /// <summary>
        /// 绑定 HTML 格式内容
        /// </summary>
        public string BindingHTML
        {
            get { return (String)GetValue(HtmlProperty); }
            set
            {
                SetValue(HtmlProperty, value);
            }
        }
        /// <summary>
        /// 绑定 XAML 格式内容
        /// </summary>
        public string BindingXAML
        {
            get { return (String)GetValue(XamlProperty); }
            set { SetValue(XamlProperty, value); }
        }
        private static void OnBindingBackGroundChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            RichTextEditor editor = (RichTextEditor)sender;
            editor.BindingBackGroundImage = (string)e.NewValue;

            System.Drawing.Image img = null;
            if (editor.BindingBackGroundImage == null)
                return;
            if (File.Exists(editor.BindingBackGroundImage))
                img = System.Drawing.Image.FromFile(editor.BindingBackGroundImage, false);

            editor.rtbXaml.Background = new ImageBrush()
            {
                ImageSource = new BitmapImage(new Uri(editor.BindingBackGroundImage)),
                TileMode = TileMode.Tile,
                Viewport = editor.BindingBackGroundImage.Contains("pack://application")
                                        ? new Rect(0, 0, 200, 200)
                                        : new Rect(0, 0, img.Width, img.Height),
                ViewportUnits = BrushMappingMode.Absolute
            };
        }
        private static void OnBindingHtmlChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            RichTextEditor editor = (RichTextEditor)sender;
            editor.BindingHTML = (string)e.NewValue;
            RichTextBoxHelper.LoadFromHtml(editor.rtbXaml, editor.BindingHTML);
            editor.Xaml = RichTextBoxHelper.GetXmal(editor.rtbXaml);
            editor.Text = RichTextBoxHelper.GetText(editor.rtbXaml);
            editor.Images = RichTextBoxHelper.GetImages(editor.Xaml);
        }
        private static void OnBindingXamlChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            RichTextEditor editor = (RichTextEditor)sender;
            editor.BindingXAML = (string)e.NewValue;
            RichTextBoxHelper.LoadFromXaml(editor.rtbXaml, editor.BindingXAML, true);
            editor.Xaml = RichTextBoxHelper.GetXmal(editor.rtbXaml);
            editor.Text = RichTextBoxHelper.GetText(editor.rtbXaml);
            editor.Images = RichTextBoxHelper.GetImages(editor.Xaml);
        }
        #endregion

        #region 依赖项属性

        //2.声明事件 
        //public static readonly RoutedEvent TextChangedEvent =
        //    EventManager.RegisterRoutedEvent("TextChangedHandler", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(RichTextEditor));
        ///// <summary>
        ///// 自定义事件，通过自定义时间为路由事件RunRoutedEvent加载、卸载方法
        ///// </summary>
        //public event RoutedEventHandler TextChangedHandler
        //{
        //    add { base.AddHandler(TextChangedEvent, value); }
        //    remove { base.RemoveHandler(TextChangedEvent, value); }
        //}
        //// This method raises the Tap event
        //private void RaiseTextChangeEvent()
        //{
        //    RoutedEventArgs rgs = new RoutedEventArgs(RichTextEditor.TextChangedEvent);
        //    RaiseEvent(rgs);
        //}
        #endregion

        #region 事件
        private void InitEvents()
        {
            #region 清除格式

            this.btnClearFormat.Click += (s, e) => RichTextBoxHelper.FormatXaml(this.rtbXaml);
            #endregion
            #region 导出文件

            //导出文件
            this.tgbtnImport.Click += (s, e) =>
            {
                string msg = RichTextBoxHelper.SaveAsFile(this.rtbXaml);
                //if (msg != null)
                //Utils.Helper.Instance.Alert(msg);
            };
            #endregion
            #region 查看 XAML 源码

            //查看 HTML 源码
            this.tgbtnSourceCode.Click += (s, e) =>
            {
                if (this.tgbtnSourceCode.IsChecked.Value)
                {
                    this.rtbXaml.Visibility = Visibility.Collapsed;
                    this.txtHtml.Visibility = Visibility.Visible;
                    string xaml = RichTextBoxHelper.GetXmal(this.rtbXaml);
                    this.txtHtml.Text = xaml;
                }
                else
                {
                    this.rtbXaml.Visibility = Visibility.Visible;
                    this.txtHtml.Visibility = Visibility.Collapsed;
                    RichTextBoxHelper.LoadFromXaml(this.rtbXaml, this.txtHtml.Text, true);
                    this.txtHtml.Text = null;
                }
            };
            #endregion
            #region 内容变化

            this.rtbXaml.TextChanged += (s, e) =>
            {
                this.Xaml = RichTextBoxHelper.GetXmal(this.rtbXaml);
            };
            #endregion
            #region 插入分段符

            this.btnInsertParagraphMark.Click += (s, e) =>
            {
                this.rtbXaml.CaretPosition.InsertParagraphBreak();
            };
            #endregion
            #region 字体颜色

            ToggleFontColor.Click += (s, e) => { ShowContextMenu(s as FrameworkElement, FontColorContextMenu); };
            ToggleLineColor.Click += (s, e) => { ShowContextMenu(s as FrameworkElement, LineColorContextMenu); };
            this.cbFontFamilyList.SelectionChanged += (s, e) =>
            {
                TextRange tr = RichTextBoxHelper.SelectedTextRange(this.rtbXaml);
                string fontFamily = this.cbFontFamilyList.SelectedValue.ToString();
                tr.ApplyPropertyValue(TextBlock.FontFamilyProperty, fontFamily);
            };
            this.cbFontSizeList.SelectionChanged += (s, e) =>
            {
                TextRange tr = RichTextBoxHelper.SelectedTextRange(this.rtbXaml);
                string fontSize = this.cbFontSizeList.SelectedValue.ToString();
                tr.ApplyPropertyValue(TextBlock.FontSizeProperty, fontSize.Replace("pt", ""));
            };
            FontColorPicker.SelectedColorChanged += (s, e) =>
            {
                TextRange tr = RichTextBoxHelper.SelectedTextRange(this.rtbXaml);
                tr.ApplyPropertyValue(TextBlock.ForegroundProperty, ReturnBrushFromString(e.Value.ToString()));
                this.FontColorContextMenu.IsOpen = false;
            };
            LineColorPicker.SelectedColorChanged += (s, e) =>
            {
                TextRange tr = RichTextBoxHelper.SelectedTextRange(this.rtbXaml);
                tr.ApplyPropertyValue(TextBlock.BackgroundProperty, ReturnBrushFromString(e.Value.ToString()));
                this.LineColorContextMenu.IsOpen = false;
            };
            #endregion
            #region 表情
            ToggleFaceImage.Click += (s, e) => { ShowContextMenu(s as FrameworkElement, FaceImageContextMenu); };
            FaceImagePicker.SelectedFaceChanged += (s, e) =>
            {
                RichTextBoxHelper.InsertImageOnCurrentPosition(this.rtbXaml, Global.FaceImagePath + e.Value, 16, 16);
            };
            #endregion
            #region 超链接

            this.btnInsetHyperlink.Click += (s, e) =>
            {
                HyperlinkDialog d = new HyperlinkDialog();
                d.Owner = this.hostedWindow;
                if (d.ShowDialog() == true)
                    RichTextBoxHelper.InsertHyperlink(this.rtbXaml, d.Model);
            };
            #endregion
            #region 插入表格

            this.btnInsetTable.Click += (s, e) =>
            {
                TableDialog d = new TableDialog();
                d.Owner = this.hostedWindow;
                if (d.ShowDialog() == true)
                    RichTextBoxHelper.InsertTable(this.rtbXaml, d.Model);
            };
            #endregion
            #region 插入图片

            this.btnInsetImage.Click += (s, e) =>
            {
                ImageDialog d = new ImageDialog();
                d.Owner = this.hostedWindow;
                if (d.ShowDialog() == true)
                {
                    RichTextBoxHelper.InsertImage(this.rtbXaml, d.Model);
                    //htmldoc.InsertImage(d.Model);
                    //imgDictionary[d.Model.ImageUrl] = d.Model;
                }
            };
            #endregion
        }
        #endregion

        #region 方法

        private void ShowContextMenu(FrameworkElement fxElement, ContextMenu cmId)
        {
            if (fxElement != null && cmId != null)
            {
                cmId.PlacementTarget = fxElement;
                cmId.Placement = System.Windows.Controls.Primitives.PlacementMode.Bottom;
                cmId.IsOpen = true;
            }
        }
        /// <summary>
        /// 将字符串转换成 System.Windows.Media.Brush 类型
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public System.Windows.Media.Brush ReturnBrushFromString(string color)
        {
            color = color.Substring(1, color.Length - 1);
            string alpha = color.Substring(0, 2);
            string red = color.Substring(2, 2);
            string green = color.Substring(4, 2);
            string blue = color.Substring(6, 2);

            byte alphaByte = Convert.ToByte(alpha, 16);
            byte redByte = Convert.ToByte(red, 16);
            byte greenByte = Convert.ToByte(green, 16);
            byte blueByte = Convert.ToByte(blue, 16);
            System.Windows.Media.Brush brush = new SolidColorBrush(System.Windows.Media.Color.FromArgb(alphaByte, redByte, greenByte, blueByte));
            return brush;
        }
        private void Lodding()
        {
            InitFontFamily();
            this.cbFontSizeList.ItemsSource = new List<MyFontSize>()
            {
               MyFontSize.XXSmall,
               MyFontSize.XSmall,
               MyFontSize.Small,
               MyFontSize.Middle,
               MyFontSize.Large,
               MyFontSize.XLarge,
               MyFontSize.XXLarge
            };
            this.cbFontSizeList.SelectedIndex = 2;

            #region ##
            /*
            string html = @"<div id='cnblogs_post_body'><div>&nbsp; &nbsp;&nbsp;<span style='font-family: 仿宋_GB2312;'><span data-wiz-span='data-wiz-span'>之前一直是做<strong>静态图片</strong>分析的，机器视觉项目如果想要<strong>在线</strong>分析，必然需要进行<strong>动态分析</strong>。前一段时间，我阅读了一些书籍，介绍了一种通过机器视觉的单向信息传输系统。主要在内外网隔离的情况下进行数据单向传输。</span></span></div>
<div><span style='font-family: 仿宋_GB2312;'><span data-wiz-span='data-wiz-span'>&nbsp; &nbsp;这样的系统，必然是真正的&ldquo;机器视觉&rdquo;系统，不仅包括图像算法的处理，而且需要包括设备的架设，并且结合多种技术（OCR,二维码），具有一定挑战意义和现实意义。这里做简单实现。</span></span></div>
<div>&nbsp;</div>
<div>&nbsp; &nbsp;一<strong>、基于OCR的单</strong><strong>向信息传输系统。</strong></div>
<div>&nbsp; &nbsp;所谓单项数据传输，书中提到的方法是采用ASCII码进行分析。但是我认为采用OCR识别的话，如果能够很好地控制住传输的信息，成功率就会很高。</div>
<div>&nbsp; &nbsp;什么信息需要单项传输？就是那些实时更新的数据，数据量不是很大但是时效性很大：比如天气、比如温度、比如时间等信息。这个信息量一旦变得很大，那么采用机器视觉的方法解决单向传输问题，就显得不是那么恰当。根据一些经验，设计这样的草图：</div>
<div>&nbsp;</div>
<div><img src='http://images.cnitblog.com/blog/508489/201501/180718418082530.png' alt='' /></div>
<div>数据不需要太多或者变化太快，只要采样的频率比变化的频率更快就可以。采用csharp</div>
<div><img src='http://images.cnitblog.com/blog/508489/201501/180719585737014.png' alt='' /></div>
<div>1）数据获取，这里基于之前介绍过的GOPre程序获得摄像头的数据</div>
<div><img src='http://images.cnitblog.com/blog/508489/201501/180720419642003.jpg' alt='' /></div>
<div>2）数据进行校正，修改成这样的结果</div>
<div><img src='http://images.cnitblog.com/blog/508489/201501/180721284331468.jpg' alt='' /></div>
<div>3）参考答题卡程序，对图像进行修正</div>
<div><img src='http://images.cnitblog.com/blog/508489/201501/180721040112805.jpg' alt='' /></div>
<div><img src='http://images.cnitblog.com/blog/508489/201501/180721494332084.jpg' alt='' /></div>
<div>
";
            //RichTextBoxHelper.SetRickTextBoxContent(this.rtbXaml, html);
             * */
            #endregion
        }

        private void InitFontFamily()
        {
            List<string> fontFamily = new List<string>();
            int srcsize = 10;

            try
            {
                using (XmlReader reader = XmlTextReader.Create(System.IO.Path.GetDirectoryName(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName) + "\\res\\htmleditor.xml"))
                {
                    XPathDocument xmlDoc = new XPathDocument(reader);
                    XPathNavigator navDoc = xmlDoc.CreateNavigator();
                    XPathNodeIterator it;
                    it = navDoc.Select(VisualFontFamiliesPath);
                    while (it.MoveNext())
                    {
                        fontFamily.Add(it.Current.Value);
                    }
                    it = navDoc.Select(SourceFontFamilyPath);
                    while (it.MoveNext())
                    {
                        break;
                    }
                    it = navDoc.Select(SourceFontSizePath);
                    while (it.MoveNext())
                    {
                        srcsize = it.Current.ValueAsInt;
                        break;
                    }
                }
                if (fontFamily.Count > 0)
                    this.cbFontFamilyList.ItemsSource = fontFamily;
            }
            catch (Exception)
            {

            }
        }
        #endregion

        #region 其它

        public event PropertyChangedEventHandler PropertyChanged;

        public void RaisePropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
    }

    #region 字体

    public sealed class MyFontSize
    {
        public int Key { get; set; }
        public double Size { get; set; }
        public string Text { get; set; }

        public static readonly MyFontSize NO = new MyFontSize { Size = 0 };
        public static readonly MyFontSize XXSmall = new MyFontSize { Key = 1, Size = 8.5, Text = "8pt" };
        public static readonly MyFontSize XSmall = new MyFontSize { Key = 2, Size = 10.5, Text = "10pt" };
        public static readonly MyFontSize Small = new MyFontSize { Key = 3, Size = 12, Text = "12pt" };
        public static readonly MyFontSize Middle = new MyFontSize { Key = 4, Size = 14, Text = "14pt" };
        public static readonly MyFontSize Large = new MyFontSize { Key = 5, Size = 18, Text = "18pt" };
        public static readonly MyFontSize XLarge = new MyFontSize { Key = 6, Size = 24, Text = "24pt" };
        public static readonly MyFontSize XXLarge = new MyFontSize { Key = 7, Size = 36, Text = "36pt" };
    }
    #endregion
}
